<?php
/**
 * Created by PhpStorm.
 * User: ownfi
 * Date: 2017-03-29
 * Time: 12:42
 */

namespace App\Services\Impl;


use App\Common\Constant\Params;
use App\Common\Constant\Status;
use App\Models\HistoryMasterBalance;
use App\Models\HistoryMasterFund;
use App\Models\MasterCash;
use App\Models\MasterFund;
use App\Models\MasterTradeLog;
use App\Models\MasterWallet;
use App\Models\Order;
use App\Services\IMasterLogService;
use App\Services\IMasterService;
use App\Services\IPayService;
use App\Services\ISystemService;
use App\Services\IWalletService;
use Crypt;
use DB;
use Log;

class WalletServiceImpl implements IWalletService
{

    private $systemService;
    private $masterLogService;

    public function __construct(ISystemService $systemService,IMasterLogService $masterLogService)
    {
        $this->systemService = $systemService;
        $this->masterLogService = $masterLogService;
    }

    public function getWalletByUserid($master_id)
    {
        return MasterWallet::firstOrCreate(['master_id'=>$master_id]);
    }

    public function issetPassword($master_id)
    {
        return !empty(MasterWallet::where(['master_id'=>$master_id])->first()->wallet_password);
    }

    public function changePassword($master_id, $password)
    {
        return MasterWallet::where(['master_id'=>$master_id])->take(1)->update([
            'wallet_password' => Crypt::encryptString($password)
        ]);
    }

    public function verifyPassword($master_id, $password)
    {
        $model = MasterWallet::where(['master_id'=>$master_id])->first();
        if ($model){
            return $password == Crypt::decryptString($model->wallet_password);
        }
        return false;
    }

    public function alipayAccountBind($master_id, $alipay_name, $alipay_account)
    {
        return MasterWallet::where(['master_id'=>$master_id])->take(1)->update([
            'alipay_name' => $alipay_name,
            'alipay_account' => $alipay_account,
        ]);
    }

    public function getCashingAmount($master_id)
    {
        return MasterCash::where(['master_id'=>$master_id,'status'=>Params::MASTER_CASH_REVIEW])->sum('amount');
    }

    public function genAssureFundOrder($master_id, $amount)
    {
        return MasterFund::create([
            'order_number'=>$this->systemService->genOrderNumber(),
            'master_id'=>$master_id,
            'amount'=>$amount,
            'status'=>Params::ORDER_STATUS_UNPAID,
        ]);
    }

    public function subtractBalance($trade_id,$master_id,$amount)
    {
        $history = HistoryMasterBalance::where('trade_id',$trade_id)->where('master_id',$master_id)->first();
        if ($history && ($history->direction == Params::TRADE_DIRECTION_OUT)){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'trade history already exists'));
            return true;
        }

        DB::beginTransaction();
        try{
            $amount = floatval($amount);

            $model = MasterWallet::where(['master_id'=>$master_id])->lockForUpdate()->first();
            if (empty($model)){
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'miss master wallet'));
                DB::rollBack();
                return false;
            }
            if (empty($model->balance) || ($model->balance < $amount)){
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'balance not enough'));
                DB::rollBack();
                return false;
            }
            $current_balance = $model->balance;
            $new_balance = $current_balance - $amount;
            $model->balance = DB::raw("balance - {$amount}");
            $model->last_trade_id = $trade_id;
            $model->last_trade_balance = $current_balance;
            $model->last_trade_time = time();
            $model->last_trade_amount = - $amount;

            $ret = HistoryMasterBalance::create([
                    'trade_id'=>$trade_id,
                    'master_id'=>$master_id,
                    'direction'=>Params::TRADE_DIRECTION_OUT,
                    'amount'=>$amount,
                    'current_balance'=>$current_balance,
                    'new_balance'=>$new_balance,
                ]) && $model->save() && MasterTradeLog::find($trade_id)->update(['status'=>Params::TRADE_STATUS_SUCCESS]);

            if ($ret){
                DB::commit();
            }else{
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'subtract fail'));
                DB::rollBack();
            }

            return $ret;
        }catch (\Exception $e){
            DB::rollBack();
            throw $e;
        }

    }

    public function raiseBalance($trade_id, $master_id, $amount)
    {
        $history = HistoryMasterBalance::where('trade_id',$trade_id)->where('master_id',$master_id)->first();
        if ($history && ($history->direction == Params::TRADE_DIRECTION_IN)){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'trade history already exists'));
            return true;
        }

        DB::beginTransaction();
        try{
            $amount = floatval($amount);

            $model = MasterWallet::where(['master_id'=>$master_id])->lockForUpdate()->first();
            if (empty($model)){
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'miss master wallet'));
                DB::rollBack();
                return false;
            }
            $current_balance = $model->balance;
            $new_balance = $current_balance + $amount;
            $model->balance = DB::raw("balance + {$amount}");
            $model->last_trade_id = $trade_id;
            $model->last_trade_balance = $current_balance;
            $model->last_trade_time = time();
            $model->last_trade_amount = $amount;

            $ret = HistoryMasterBalance::create([
                    'trade_id'=>$trade_id,
                    'master_id'=>$master_id,
                    'direction'=>Params::TRADE_DIRECTION_IN,
                    'amount'=>$amount,
                    'current_balance'=>$current_balance,
                    'new_balance'=>$new_balance,
                ]) && $model->save() && MasterTradeLog::find($trade_id)->update(['status'=>Params::TRADE_STATUS_SUCCESS]);

            if ($ret){
                DB::commit();
            }else{
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'raise fail'));
                DB::rollBack();
            }

            return $ret;
        }catch (\Exception $e){
            DB::rollBack();
            throw $e;
        }
    }

    public function subtractAssureFund($trade_id, $master_id, $amount)
    {
        $history = HistoryMasterFund::where('trade_id',$trade_id)->where('master_id',$master_id)->first();
        if ($history && ($history->direction == Params::TRADE_DIRECTION_OUT)){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'trade history already exists'));
            return true;
        }

        DB::beginTransaction();
        try{
            $amount = floatval($amount);

            $model = MasterWallet::where(['master_id'=>$master_id])->lockForUpdate()->first();
            if (empty($model)){
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'miss master wallet'));
                DB::rollBack();
                return false;
            }
            if (empty($model->assure_fund) || ($model->assure_fund < $amount)){
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'assure fund not enough'));
                DB::rollBack();
                return false;
            }
            $current_balance = $model->assure_fund;
            $new_balance = $current_balance - $amount;
            $model->assure_fund = DB::raw("assure_fund - {$amount}");

            $ret = HistoryMasterFund::create([
                    'trade_id'=>$trade_id,
                    'master_id'=>$master_id,
                    'direction'=>Params::TRADE_DIRECTION_OUT,
                    'amount'=>$amount,
                    'current_balance'=>$current_balance,
                    'new_balance'=>$new_balance,
                ]) && $model->save() && MasterTradeLog::find($trade_id)->update(['status'=>Params::TRADE_STATUS_SUCCESS]);

            if ($ret){
                DB::commit();
            }else{
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'subtract fail'));
                DB::rollBack();
            }

            return $ret;
        }catch (\Exception $e){
            DB::rollBack();
            throw $e;
        }
    }

    public function raiseAssureFund($trade_id, $master_id, $amount)
    {
        $history = HistoryMasterFund::where('trade_id',$trade_id)->where('master_id',$master_id)->first();
        if ($history && ($history->direction == Params::TRADE_DIRECTION_IN)){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'trade history already exists'));
            return true;
        }

        DB::beginTransaction();
        try{
            $amount = floatval($amount);

            $model = MasterWallet::where(['master_id'=>$master_id])->lockForUpdate()->first();
            if (empty($model)){
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'miss master wallet'));
                DB::rollBack();
                return false;
            }
            $current_balance = $model->assure_fund;
            $new_balance = $current_balance + $amount;
            $model->assure_fund = DB::raw("assure_fund + {$amount}");

            $ret = HistoryMasterFund::create([
                    'trade_id'=>$trade_id,
                    'master_id'=>$master_id,
                    'direction'=>Params::TRADE_DIRECTION_IN,
                    'amount'=>$amount,
                    'current_balance'=>$current_balance,
                    'new_balance'=>$new_balance,
                ]) && $model->save() && MasterTradeLog::find($trade_id)->update(['status'=>Params::TRADE_STATUS_SUCCESS]);

            if ($ret){
                DB::commit();
            }else{
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'raise fail'));
                DB::rollBack();
            }

            return $ret;
        }catch (\Exception $e){
            DB::rollBack();
            throw $e;
        }
    }

    public function punish($trade_id, $master_id, $amount)
    {
        $history = HistoryMasterBalance::where('trade_id',$trade_id)->where('master_id',$master_id)->first();
        if ($history && ($history->direction == Params::TRADE_DIRECTION_OUT)){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'trade history already exists'));
            return true;
        }

        DB::beginTransaction();
        try{
            $amount = floatval($amount);

            $model = MasterWallet::where(['master_id'=>$master_id])->lockForUpdate()->first();
            $current_balance = $model->balance;
            $new_balance = $current_balance - $amount;
            $model->balance = DB::raw("balance - {$amount}");
            $model->last_trade_id = $trade_id;
            $model->last_trade_balance = $current_balance;
            $model->last_trade_time = time();
            $model->last_trade_amount = - $amount;

            $ret = HistoryMasterBalance::create([
                    'trade_id'=>$trade_id,
                    'master_id'=>$master_id,
                    'direction'=>Params::TRADE_DIRECTION_OUT,
                    'amount'=>$amount,
                    'current_balance'=>$current_balance,
                    'new_balance'=>$new_balance,
                ]) && $model->save() && MasterTradeLog::find($trade_id)->update(['status'=>Params::TRADE_STATUS_SUCCESS]);

            if ($ret){
                DB::commit();
            }else{
                Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'punish fail'));
                DB::rollBack();
            }

            return $ret;
        }catch (\Exception $e){
            DB::rollBack();
            throw $e;
        }
    }

}